from sqlalchemy.orm import Session
from sqlalchemy import or_
from app.db.models.chat import Room, RoomMember, Message
from app.db.models.user import User, Apply
from datetime import datetime
from typing import List, Dict, Any, Optional, Tuple

class RoomService:
    @staticmethod
    def create_room(db: Session, user_id: int, name: str, description: str = None, avatar: str = None) -> Dict[str, Any]:
        """创建群聊房间"""
        # 创建群聊房间
        new_room = Room(
            name=name,
            avatar=avatar or "",
            creator_id=user_id,
            type=1,  # 1表示群聊
            member_count=1,
            description=description,  # 添加群描述
            created_at=datetime.now()
        )
        db.add(new_room)
        db.flush()
        
        # 添加创建者为群成员，并设置为群主
        room_member = RoomMember(
            room_id=new_room.id,
            user_id=user_id,
            nickname=db.query(User).filter(User.id == user_id).first().nickname,
            role=2,  # 2表示群主
            created_at=datetime.now()
        )
        db.add(room_member)
        db.commit()
        db.refresh(new_room)
        
        # 构建返回数据
        return {
            "id": new_room.id,
            "conversationId": new_room.id,
            "roomId": new_room.id,
            "name": new_room.name,
            "description": new_room.description or "",  # 返回群描述
            "avatar": new_room.avatar,
            "ownerId": new_room.creator_id,
            "memberCount": new_room.member_count,
            "onlineCount": 1,  # 创建者在线
            "createTime": new_room.created_at.strftime("%Y-%m-%d %H:%M:%S") if new_room.created_at else ""
        }
    
    @staticmethod
    def get_user_rooms(db: Session, user_id: int) -> List[Dict[str, Any]]:
        """获取用户加入的群聊列表"""
        # 查询用户加入的所有群聊
        user_rooms = db.query(Room).join(
            RoomMember, Room.id == RoomMember.room_id
        ).filter(
            RoomMember.user_id == user_id,
            Room.type == 1  # 1表示群聊
        ).all()
        
        room_list = []
        for room in user_rooms:
            # 计算在线成员数
            online_count = db.query(User).join(
                RoomMember, User.id == RoomMember.user_id
            ).filter(
                RoomMember.room_id == room.id,
                User.online == True
            ).count()
            
            room_list.append({
                "id": room.id,
                "conversationId": room.id,  # 使用room_id作为会话ID
                "roomId": room.id,
                "name": room.name,
                "description": room.description or "",  # 添加群描述
                "avatar": room.avatar,
                "ownerId": room.creator_id,
                "memberCount": room.member_count,
                "onlineCount": online_count,
                "createTime": room.created_at.strftime("%Y-%m-%d %H:%M:%S") if room.created_at else ""
            })
        
        return room_list
    
    @staticmethod
    def get_room_detail(db: Session, room_id: int, user_id: int) -> Optional[Dict[str, Any]]:
        """获取群聊详情"""
        # 查询群聊
        room = db.query(Room).filter(Room.id == room_id, Room.type == 1).first()
        if not room:
            return None
        
        # 验证用户是否为群成员
        member = db.query(RoomMember).filter(
            RoomMember.room_id == room_id,
            RoomMember.user_id == user_id
        ).first()
        if not member:
            return None
        
        # 获取群成员列表
        members = db.query(User, RoomMember).join(
            RoomMember, User.id == RoomMember.user_id
        ).filter(
            RoomMember.room_id == room_id
        ).all()
        
        member_list = []
        online_count = 0
        for user, room_member in members:
            member_list.append({
                "id": user.id,
                "nickname": user.nickname,
                "avatar": user.avatar,
                "role": room_member.role,
                "online": 1 if user.online else 0
            })
            if user.online:
                online_count += 1
        
        # 构建返回数据
        return {
            "id": room.id,
            "conversationId": room.id,
            "roomId": room.id,
            "name": room.name,
            "description": room.description or "",  # 添加群描述
            "announcement": "",  # Room模型中没有announcement字段，这里留空
            "avatar": room.avatar,
            "ownerId": room.creator_id,
            "memberCount": room.member_count,
            "onlineCount": online_count,
            "createTime": room.created_at.strftime("%Y-%m-%d %H:%M:%S") if room.created_at else "",
            "members": member_list
        }
    
    @staticmethod
    def invite_users(db: Session, room_id: int, user_id: int, target_user_ids: List[int]) -> int:
        """邀请用户加入群聊"""
        # 查询群聊
        room = db.query(Room).filter(Room.id == room_id, Room.type == 1).first()
        if not room:
            return 0
        
        # 验证当前用户是否为群成员
        member = db.query(RoomMember).filter(
            RoomMember.room_id == room_id,
            RoomMember.user_id == user_id
        ).first()
        if not member:
            return 0
        
        # 添加新成员
        added_count = 0
        for target_id in target_user_ids:
            # 检查用户是否存在
            user = db.query(User).filter(User.id == target_id).first()
            if not user:
                continue
            
            # 检查是否已经是群成员
            existing = db.query(RoomMember).filter(
                RoomMember.room_id == room_id,
                RoomMember.user_id == target_id
            ).first()
            if existing:
                continue
            
            # 添加为群成员
            new_member = RoomMember(
                room_id=room_id,
                user_id=target_id,
                nickname=user.nickname,
                role=0,  # 0表示普通成员
                created_at=datetime.now()
            )
            db.add(new_member)
            added_count += 1
        
        if added_count > 0:
            # 更新群成员数量
            room.member_count += added_count
            db.commit()
        
        return added_count
    
    @staticmethod
    def exit_room(db: Session, room_id: int, user_id: int) -> bool:
        """退出群聊"""
        # 查询群聊
        room = db.query(Room).filter(Room.id == room_id, Room.type == 1).first()
        if not room:
            return False
        
        # 验证用户是否为群成员
        member = db.query(RoomMember).filter(
            RoomMember.room_id == room_id,
            RoomMember.user_id == user_id
        ).first()
        if not member:
            return False
        
        # 如果是群主，不允许直接退出
        if member.role == 2:
            return False
        
        # 删除群成员记录
        db.delete(member)
        
        # 更新群成员数量
        room.member_count -= 1
        db.commit()
        
        return True
    
    @staticmethod
    def disband_room(db: Session, room_id: int, user_id: int) -> bool:
        """解散群聊(群主)"""
        # 查询群聊
        room = db.query(Room).filter(Room.id == room_id, Room.type == 1).first()
        if not room:
            return False
        
        # 验证用户是否为群主
        member = db.query(RoomMember).filter(
            RoomMember.room_id == room_id,
            RoomMember.user_id == user_id,
            RoomMember.role == 2  # 2表示群主
        ).first()
        if not member:
            return False
        
        # 获取所有群成员ID，用于后续发送解散通知
        room_members = db.query(RoomMember).filter(RoomMember.room_id == room_id).all()
        member_ids = [rm.user_id for rm in room_members]
        
        # 先删除与该群聊相关的所有申请记录
        from app.db.models.user import Apply
        db.query(Apply).filter(Apply.room_id == room_id).delete()
        
        # 删除所有群成员记录
        db.query(RoomMember).filter(RoomMember.room_id == room_id).delete()
        
        # 删除群聊消息
        db.query(Message).filter(Message.room_id == room_id).delete()
        
        # 删除群聊
        db.delete(room)
        db.commit()
        
        # 通过WebSocket通知所有群成员群聊已被解散
        try:
            from app.api.ws import ws_handler
            
            # 构建通知消息
            notification = {
                "type": 27,  # 群聊解散通知
                "body": {
                    "roomId": room_id,
                    "message": f"群聊已被解散",
                    "disbandedBy": user_id
                }
            }
            
            # 向所有成员发送通知
            import asyncio
            for member_id in member_ids:
                if member_id in ws_handler.active_connections:
                    print(f"发送群聊解散通知给用户 {member_id}")
                    asyncio.create_task(ws_handler.send_message(member_id, notification))
        except Exception as e:
            # 记录错误但不中断流程
            from loguru import logger
            logger.error(f"WebSocket通知群聊解散失败: {str(e)}")
        
        return True
        
    @staticmethod
    def get_room_members(db: Session, room_id: int, page: int = 1, page_size: int = 20, keyword: str = None) -> Tuple[List[Dict[str, Any]], int]:
        """获取群成员列表（分页）"""
        # 查询群聊
        room = db.query(Room).filter(Room.id == room_id, Room.type == 1).first()
        if not room:
            return [], 0
            
        # 构建查询
        query = db.query(User, RoomMember).join(
            RoomMember, User.id == RoomMember.user_id
        ).filter(
            RoomMember.room_id == room_id
        )
        
        # 如果有关键词，添加过滤条件
        if keyword:
            query = query.filter(
                or_(
                    User.nickname.like(f"%{keyword}%"),
                    RoomMember.nickname.like(f"%{keyword}%")
                )
            )
            
        # 计算总数
        total = query.count()
        
        # 分页
        members = query.offset((page - 1) * page_size).limit(page_size).all()
        
        # 构建返回数据
        member_list = []
        for user, room_member in members:
            member_list.append({
                "id": user.id,
                "nickname": user.nickname,
                "avatar": user.avatar,
                "role": room_member.role,
                "online": 1 if user.online else 0,
            })
            
        return member_list, total
    
    @staticmethod
    def search_groups(db: Session, keyword: str, user_id: int) -> List[Dict[str, Any]]:
        """搜索群聊"""
        # 搜索包含关键词的群聊
        rooms = db.query(Room).filter(
            Room.name.like(f"%{keyword}%"),
            Room.type == 1  # 1表示群聊
        ).all()
        
        # 获取用户已加入的群聊ID列表
        user_room_ids = db.query(RoomMember.room_id).filter(
            RoomMember.user_id == user_id
        ).all()
        user_room_ids = [r.room_id for r in user_room_ids]
        
        # 获取用户已申请的群聊ID列表
        from app.db.models.user import Apply
        user_applying_rooms = db.query(Apply.room_id, Apply.status).filter(
            Apply.applicant_id == user_id,
            Apply.type == 1,  # 群聊申请，修改为1以匹配前端
            Apply.room_id.in_([room.id for room in rooms])  # 只查询搜索结果中的群聊
        ).all()
        
        # 构建申请状态映射
        applying_status = {}
        for room_id, status in user_applying_rooms:
            applying_status[room_id] = status
        
        result = []
        for room in rooms:
            # 转换为响应格式
            room_data = {
                "id": room.id,
                "name": room.name,
                "avatar": room.avatar,
                "description": "",  # Room模型中没有description字段，这里留空
                "memberCount": room.member_count or 0,
                "joined": room.id in user_room_ids,
                "applying": room.id in applying_status and applying_status[room.id] == 0  # 0表示待审核
            }
            result.append(room_data)
            
        return result
    
    @staticmethod
    def join_group(db: Session, room_id: int, user_id: int) -> bool:
        """申请加入群聊"""
        # 检查群聊是否存在
        room = db.query(Room).filter(Room.id == room_id, Room.type == 1).first()
        if not room:
            return False
        
        # 检查用户是否已在群聊中
        existing_member = db.query(RoomMember).filter(
            RoomMember.room_id == room_id,
            RoomMember.user_id == user_id
        ).first()
        
        if existing_member:
            return True  # 已经是群成员
            
        # 检查是否已有待处理的申请
        existing_apply = db.query(Apply).filter(
            Apply.applicant_id == user_id,
            Apply.room_id == room_id,
            Apply.type == 1,  # 群聊申请，修改为1以匹配前端
            Apply.status == 0  # 待审核
        ).first()
        
        if existing_apply:
            return True  # 已经申请过，等待审核
            
        # 获取用户信息
        user = db.query(User).filter(User.id == user_id).first()
        if not user:
            return False
            
        # 创建加群申请
        apply = Apply(
            applicant_id=user_id,
            room_id=room_id,
            content="申请加入群聊",
            type=1,  # 群聊申请，修改为1以匹配前端
            status=0  # 待审核
        )
        db.add(apply)
        db.commit()
        
        # 尝试通过WebSocket通知群主
        try:
            from app.api.ws import ws_handler
            # 获取群主ID
            owner = db.query(RoomMember).filter(
                RoomMember.room_id == room_id,
                RoomMember.role == 2  # 群主
            ).first()
            
            if owner and owner.user_id in ws_handler.active_connections:
                # 构建通知消息
                notification = {
                    "type": 25,  # 群聊申请，使用新的类型值
                    "body": {
                        "id": apply.id,
                        "userId": user_id,
                        "roomId": room_id,
                        "content": "申请加入群聊",
                        "type": 2,
                        "status": 0,
                        "createdAt": apply.created_at.strftime("%Y-%m-%d %H:%M:%S") if apply.created_at else datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                        "user": {
                            "id": user_id,
                            "nickname": user.nickname,
                            "sex": user.sex or 0,
                            "online": 1 if user.online else 0
                        },
                        "room": {
                            "id": room.id,
                            "name": room.name,
                            "avatar": room.avatar
                        }
                    }
                }
                import asyncio
                asyncio.create_task(ws_handler.send_message(owner.user_id, notification))
        except Exception as e:
            # 记录错误但不中断流程
            from loguru import logger
            logger.error(f"WebSocket通知群聊申请失败: {str(e)}")
        
        return True
    
    @staticmethod
    def review_join_apply(db: Session, apply_id: int, user_id: int, status: int) -> bool:
        """审核群聊加入申请
        
        Args:
            db: 数据库会话
            apply_id: 申请ID
            user_id: 审核人ID（群主或管理员）
            status: 审核状态 1-通过 2-拒绝
            
        Returns:
            bool: 是否操作成功
        """
        from app.db.models.user import Apply
        
        # 获取申请信息
        apply = db.query(Apply).filter(
            Apply.id == apply_id,
            Apply.type == 1,  # 群聊申请，修改为1以匹配前端和join_group函数
            Apply.status == 0  # 待审核
        ).first()
        
        if not apply:
            return False
            
        # 检查审核人是否有权限（是否为群主或管理员）
        room_member = db.query(RoomMember).filter(
            RoomMember.room_id == apply.room_id,
            RoomMember.user_id == user_id,
            RoomMember.role.in_([1, 2])  # 1-管理员 2-群主
        ).first()
        
        if not room_member:
            return False
            
        # 更新申请状态
        apply.status = status
        
        # 如果通过申请，添加用户到群聊
        if status == 1:
            # 获取申请人信息
            applicant = db.query(User).filter(User.id == apply.applicant_id).first()
            if not applicant:
                db.rollback()
                return False
                
            # 添加用户到群聊
            new_member = RoomMember(
                room_id=apply.room_id,
                user_id=apply.applicant_id,
                nickname=applicant.nickname,
                role=0,  # 普通成员
                created_at=datetime.now()
            )
            db.add(new_member)
            
            # 更新群成员数量
            room = db.query(Room).filter(Room.id == apply.room_id).first()
            if room:
                room.member_count = (room.member_count or 0) + 1
                
        db.commit()
        
        # 尝试通过WebSocket通知申请人
        try:
            from app.api.ws import ws_handler
            
            if apply.applicant_id in ws_handler.active_connections:
                # 获取群聊信息
                room = db.query(Room).filter(Room.id == apply.room_id).first()
                
                # 构建通知消息
                notification = {
                    "type": 26,  # 群聊申请结果，使用新的类型值
                    "body": {
                        "id": apply.id,
                        "status": status,
                        "roomId": apply.room_id,
                        "roomName": room.name if room else "",
                        "roomAvatar": room.avatar if room else "",
                        "message": "您的加群申请已通过" if status == 1 else "您的加群申请被拒绝"
                    }
                }
                import asyncio
                print(f"发送群聊申请结果通知给用户 {apply.applicant_id}: {notification}")
                asyncio.create_task(ws_handler.send_message(apply.applicant_id, notification))
        except Exception as e:
            # 记录错误但不中断流程
            from loguru import logger
            logger.error(f"WebSocket通知申请结果失败: {str(e)}")
            
        return True
    
    @staticmethod
    def get_room_applies(db: Session, room_id: int, status: int = 0, page: int = 1, page_size: int = 20) -> Tuple[List[Dict[str, Any]], int]:
        """获取群聊申请列表
        
        Args:
            db: 数据库会话
            room_id: 群聊ID
            status: 申请状态 0-待审核 1-已通过 2-已拒绝
            page: 页码
            page_size: 每页数量
            
        Returns:
            Tuple[List[Dict[str, Any]], int]: 申请列表和总数
        """
        from app.db.models.user import Apply
        
        # 构建查询
        query = db.query(Apply, User).join(
            User, Apply.applicant_id == User.id
        ).filter(
            Apply.room_id == room_id,
            Apply.type == 1,  # 群聊申请，修改为1以匹配前端和join_group函数
            Apply.status == status
        )
        
        # 计算总数
        total = query.count()
        
        # 分页
        applies = query.order_by(Apply.created_at.desc()).offset((page - 1) * page_size).limit(page_size).all()
        
        # 构建返回数据
        apply_list = []
        for apply, user in applies:
            apply_list.append({
                "id": apply.id,
                "userId": user.id,
                "nickname": user.nickname,
                "avatar": user.avatar,
                "content": apply.content,
                "status": apply.status,
                "createdAt": apply.created_at.strftime("%Y-%m-%d %H:%M:%S") if apply.created_at else ""
            })
            
        return apply_list, total 